﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace ExcelFileQueryTool
{
    public partial class frmClientLogList : Form
    {
        SortableBindingList<ExcelWorkLogItem> _source;

        CrmPeopleService _peopleService = new CrmPeopleService(AppConfig.DBConnectionString);

        BillSalesService _salesService = new BillSalesService(AppConfig.DBConnectionString);

        ExcelWorkLogService _workLogService;

        public frmClientLogList(SortableBindingList<ExcelWorkLogItem> source, ExcelWorkLogService logSvc)
        {
            InitializeComponent();

            _source = source;
            _workLogService = logSvc;

            if (_source != null && _source.Count() > 0)
            {
                var isLoadingFeeWarned = _source.Any(x => x.HasRecordOnBook == false
                    && x.类型 == "进货"
                    && x.货物.EndsWith("水泥")
                    && x.运装卸费 != 0);

                if (isLoadingFeeWarned)
                {
                    MessageDispatcherManager.DispatchMessage(
                        new AppMessage
                        {
                            Level = AppMessageLevel.Info,
                            Time = DateTime.Now,
                            Title = "进货运费风险提示",
                            Content = "当前可入账的记录存在运费多算给供应商的风险，请认真检查后再入账！"
                        });
                }

                this.txtClientProvider.Text = _source.First().客户供应商;

                //todo:allow multiple selection
                const string TYPE_ALL = "所有";
                cboxLogType.Items.Add(TYPE_ALL);
                cboxLogType.SelectedItem = TYPE_ALL;
                foreach (var t in source.Where(x => x.HasRecordOnBook == false).Select(x => x.类型).Distinct())
                {
                    cboxLogType.Items.Add(t);
                }

                cboxLogType.SelectedIndexChanged += (sender, e) =>
                {
                    var dgv = (ExcelWorkLogGrid)this.panelContainer.Controls[GRID_CONTROL_NAME];
                    var cbox = (ToolStripComboBox)sender;
                    var selectedType = (string)cbox.SelectedItem;

                    var manager = (CurrencyManager)this.BindingContext[dgv.DataSource];
                    manager.SuspendBinding();

                    foreach (DataGridViewRow row in dgv.Rows)
                    {
                        var obj = (ExcelWorkLogItem)row.DataBoundItem;

                        if (dgv.ShowRecorded == false && obj.HasRecordOnBook)
                            continue;

                        row.Visible = (selectedType == TYPE_ALL)
                                    || selectedType == obj.类型;

                    }

                    manager.ResumeBinding();
                };
            }

            LoadGridControl();
        }

        const String GRID_CONTROL_NAME = "dgvData";

        private void LoadGridControl()
        {
            if (this.panelContainer.Controls.ContainsKey(GRID_CONTROL_NAME))
                this.panelContainer.Controls.RemoveByKey(GRID_CONTROL_NAME);

            var grid = new ExcelWorkLogGrid(new string[] { "客户供应商" }, "货物") { DataSource = _source };
            grid.CellDoubleClick += grid_CellDoubleClick;
            grid.Dock = DockStyle.Fill;
            grid.Location = new Point(0, 25);
            grid.Size = new Size(400, 300);
            grid.Name = GRID_CONTROL_NAME;

            this.panelContainer.Controls.Add(grid);
        }

        void grid_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            var grid = (ExcelWorkLogGrid)sender;
            var log = (ExcelWorkLogItem)grid.Rows[e.RowIndex].DataBoundItem;
            using (var f = new frmClientLogDetail(log, _workLogService))
            {
                f.ShowDialog();
            }

            if (log.客户供应商.Equals(txtClientProvider.Text.Trim()) == false)
            {
                grid.Rows.RemoveAt(e.RowIndex);
            }

            grid.Refresh();
        }

        private void btnClose_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void btnMarkAllAsRecorded_Click(object sender, EventArgs e)
        {
            if (_workLogService.FileHasChanged)
            {
                MessageDispatcherManager.DispatchMessage(
                    new AppMessage
                    {
                        Level = AppMessageLevel.Info,
                        Time = DateTime.Now,
                        Title = "客户记录操作",
                        Content = "已检测到文件有变动，请返回主界面重新载入日志数据"
                    }
                );

                return;
            }

            var dgv = this.panelContainer.Controls[GRID_CONTROL_NAME] as DataGridView;
            if (dgv == null)
                throw new Exception("当前视图不支持[保存所有]功能，请切换至BasicGrid!");

            var displayedLogs = GetDisplayedLogs(dgv);

            if (displayedLogs.Count() == 0)
                return;

            if (displayedLogs.Count() > 1 && MessageBox.Show("是否将当前列表的所有记录标记为已记录？", "标记所有记录", MessageBoxButtons.YesNo) != DialogResult.Yes)
                return;

            _workLogService.MarkAsRecordedOnBook(displayedLogs);

            if (IndicateWhetherCloseForm())
                this.Close();
        }

        private static IEnumerable<ExcelWorkLogItem> GetDisplayedLogs(DataGridView dgv)
        {
            return dgv.Rows.Cast<DataGridViewRow>().Where(x => x.Visible).Cast<DataGridViewRow>().Select(r => (ExcelWorkLogItem)r.DataBoundItem);
        }

        private void btnSaveAllToFile_Click(object sender, EventArgs e)
        {
            if (_workLogService.FileHasChanged)
            {
                MessageDispatcherManager.DispatchMessage(
                    new AppMessage
                    {
                        Level = AppMessageLevel.Info,
                        Time = DateTime.Now,
                        Title = "客户记录操作",
                        Content = "已检测到文件有变动，请返回主界面重新载入日志数据"
                    }
                );

                return;
            }

            var dgv = this.panelContainer.Controls[GRID_CONTROL_NAME] as DataGridView;
            if (dgv == null)
                throw new Exception("当前视图不支持[保存所有]功能，请切换至BasicGrid!");

            var displayedLogs = GetDisplayedLogs(dgv);

            if (displayedLogs.Count() == 0)
                return;

            var salesList = ClientFileService.ConvertToBillSales(displayedLogs, _peopleService, true);
            DoSaveWithUIAction(salesList, _source);
        }

        private void btnSaveSelectedToFile_Click(object sender, EventArgs e)
        {
            if (_workLogService.FileHasChanged)
            {
                MessageDispatcherManager.DispatchMessage(
                    new AppMessage
                    {
                        Level = AppMessageLevel.Info,
                        Time = DateTime.Now,
                        Title = "客户记录操作",
                        Content = "已检测到文件有变动，请返回主界面重新载入日志数据"
                    }
                );

                return;
            }

            var dgv = this.panelContainer.Controls[GRID_CONTROL_NAME] as DataGridView;
            if (dgv == null)
                throw new Exception("当前视图不支持[保存选定]功能，请切换至BasicGrid!");

            var selectedRows = GetSelectedAndVisibleRows(dgv);
            var logs = selectedRows.Cast<DataGridViewRow>().Select(r => (ExcelWorkLogItem)r.DataBoundItem);

            if (logs.Count() == 0)
                return;

            var salesList = ClientFileService.ConvertToBillSales(logs, _peopleService, true);
            DoSaveWithUIAction(salesList, logs);
        }

        private bool IndicateWhetherCloseForm()
        {
            return _source.All(x => x.HasRecordOnBook);
        }

        private void btnSaveAgentPay_Click(object sender, EventArgs e)
        {
            if (_workLogService.FileHasChanged)
            {
                MessageDispatcherManager.DispatchMessage(
                    new AppMessage
                    {
                        Level = AppMessageLevel.Info,
                        Time = DateTime.Now,
                        Title = "客户记录操作",
                        Content = "已检测到文件有变动，请返回主界面重新载入日志数据"
                    }
                );

                return;
            }

            var dgv = this.panelContainer.Controls[GRID_CONTROL_NAME] as DataGridView;
            if (dgv == null)
                throw new Exception("当前视图不支持[保存代收功能，请切换至BasicGrid!");

            var selectedRows = GetSelectedAndVisibleRows(dgv);
            var logs = selectedRows.Cast<DataGridViewRow>().Select(r => (ExcelWorkLogItem)r.DataBoundItem);

            if (logs.Count() == 0)
                return;

            if (logs.Count() != 1)
                throw new Exception("保存操作已被终止！保存代收操作只允许同时操作一条记录。");

            var salesList = ClientFileService.ConvertToBillSales(logs, _peopleService, true);

            var count = salesList.Count();

            if (count == 0)
                return;

            if (count == 1)
            {
                if (salesList.First().BillType != (short)BillSalesType.Income
                    && salesList.First().BillType != (short)BillSalesType.Pay)
                    throw new Exception("保存操作已被终止！因为当前记录不满足代收条件，请执行其它保存操作。");
            }
            else
            {
                foreach (var clientSalesGroup in salesList.GroupBy(x => x.ClientName))
                {
                    DoSaveWithUIAction(clientSalesGroup.ToArray(), logs);
                }
            }
        }

        private void DoSaveWithUIAction(IEnumerable<BillSales> salesList, IEnumerable<ExcelWorkLogItem> logs)
        {
            var firstName = salesList.First().ClientName; // 不能用txtClientProvider的值，因为这样会保存不了代收记录

            if (salesList.Any(x => x.ClientName != firstName))
                throw new Exception("保存操作已被终止！因为当前保存的记录中包含有代收记录，请对这些记录进行单独操作。");

            var autoConfirmBillNumber = AppConfig.BillNotRequiredClients.Contains(firstName);

            if (autoConfirmBillNumber)
            {
                foreach (var sale in salesList)
                {
                    sale.BillNumber = "已确认";
                }
            }

            salesList = salesList.OrderBy(x => x.SalesDate);

            string clientFile;
            var saved = SaveToFile(firstName, salesList, out clientFile);

            if (saved)
            {
                //NOTE: 
                // 1.客户名称可能会有差别，选择了文件后，可能与传入的值不同，另外提供功能进行修复
                // 2.可能在保存文件过程中创建了用户资料，也需要在这里重新赋值ClientId和名称
                var client_name_from_file = ClientFileService.GetClientNameFromFile(clientFile);
                if (firstName != client_name_from_file
                    || salesList.First().ClientId == ClientFileService.DEFAULT_INVALID_CLIENT_ID)
                {
                    var clientId = ClientFileService.GetClientId(client_name_from_file, _peopleService);

                    foreach (var item in salesList)
                    {
                        item.ClientId = clientId;
                        item.ClientName = client_name_from_file;
                    }
                }

                // 如果没有找到客户记录，则根据对数表自动建立客户记录，并修复历史记录的ClientId
                if (salesList.First().ClientId == ClientFileService.DEFAULT_INVALID_CLIENT_ID)
                {
                    var curClientName = salesList.First().ClientName;

                    var people = new CRMPeople
                    {
                        CreatedTime = DateTime.Now,
                        Gender = "男",
                        IndexCode = StringHelper.ChinessWordToPinYin(curClientName),
                        LastUpdatedTime = DateTime.Now,
                        Name = curClientName,
                        NickName = null,
                        Note = null,
                        Status = 0,
                        TypeCode = ClientFileService.GetClientTypeFromFile(clientFile)
                    };

                    var infoArr = ClientFileService.RetriveContactInfoFromFile(clientFile);
                    if (infoArr != null)
                    {
                        people.Telephone = infoArr[1];
                        people.Address = infoArr[2];
                    }

                    var curClientId = _peopleService.Add(people);
                    _salesService.UpdateClientIdByName(curClientName, curClientId);
                }

                SaveToDB(salesList);
                _workLogService.MarkAsRecordedOnBook(logs);

                var dgv = (ExcelWorkLogGrid)this.panelContainer.Controls[GRID_CONTROL_NAME];
                dgv.RefreshVisibilityByRecordedStatus();

                // open the file to fix excel format and formula manully
                if (MessageBox.Show("保存成功，需要打开客户文件吗？", "提示", MessageBoxButtons.YesNo) == DialogResult.Yes)
                    using (Process.Start(clientFile)) { }
            }

            if (saved && IndicateWhetherCloseForm())
                this.Close();
        }

        private bool SaveToFile(string clientName, IEnumerable<BillSales> salesList, out string fileName)
        {
            bool succeed = false;

            string sheetName = null;
            fileName = null;

            var salesYear = salesList.First().SalesDate.Year.ToString();
            var note = salesList.First().Note;

            using (var f = new frmRecordOnBookSingle(clientName, salesYear, note))
            {
                if (f.ShowDialog() == DialogResult.OK)
                {
                    fileName = f.ClientFile;
                    sheetName = f.TargetSheetName;

                    ClientFileService service = new ClientFileService(fileName);
                    service.Save(salesList, sheetName);
                    succeed = true;
                }
            }

            return succeed;
        }

        private void SaveToDB(IEnumerable<BillSales> salesList)
        {
            _salesService.Add(salesList);
        }

        private IEnumerable<DataGridViewRow> GetSelectedAndVisibleRows(DataGridView dgv)
        {
            var selectedRows = dgv.SelectedRows;

            if (selectedRows == null)
                return null;

            return selectedRows.Cast<DataGridViewRow>().Where(x => x.Visible).ToList();
        }

        private void btnMarkSelectedAsRecorded_Click(object sender, EventArgs e)
        {
            if (_workLogService.FileHasChanged)
            {
                MessageDispatcherManager.DispatchMessage(
                    new AppMessage
                    {
                        Level = AppMessageLevel.Info,
                        Time = DateTime.Now,
                        Title = "客户记录操作",
                        Content = "已检测到文件有变动，请返回主界面重新载入日志数据"
                    }
                );

                return;
            }

            var dgv = (ExcelWorkLogGrid)this.panelContainer.Controls[GRID_CONTROL_NAME];
            var selectedRows = GetSelectedAndVisibleRows(dgv);
            var logs = selectedRows.Select(r => (ExcelWorkLogItem)r.DataBoundItem);

            if (logs.Count() == 0)
                return;

            _workLogService.MarkAsRecordedOnBook(logs);
            dgv.RefreshVisibilityByRecordedStatus();

            selectedRows = GetSelectedAndVisibleRows(dgv);
            if (selectedRows == null || selectedRows.Count() == 0)
                this.Close();
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            switch (keyData)
            {
                case Keys.F1:
                    btnSaveSelectedToFile.PerformClick();
                    break;

                case Keys.F2:
                    btnSaveAllToFile.PerformClick();
                    break;

                case Keys.F3:
                    btnMarkSelectedAsRecorded.PerformClick();
                    break;

                case Keys.F4:
                    btnMarkAllAsRecorded.PerformClick();
                    break;

                case Keys.F5:
                    btnSaveAgentPay.PerformClick();
                    break;

                case Keys.F6:
                    btnClearPayment.PerformClick();
                    break;

                default:
                    break;
            }

            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void btnClearPayment_Click(object sender, EventArgs e)
        {
            if (_workLogService.FileHasChanged)
            {
                MessageDispatcherManager.DispatchMessage(
                    new AppMessage
                    {
                        Level = AppMessageLevel.Info,
                        Time = DateTime.Now,
                        Title = "客户记录操作",
                        Content = "已检测到文件有变动，请返回主界面重新载入日志数据"
                    }
                );

                return;
            }

            var dgv = (ExcelWorkLogGrid)this.panelContainer.Controls[GRID_CONTROL_NAME];

            var selectedRows = GetSelectedAndVisibleRows(dgv);
            var logs = selectedRows.Select(r => (ExcelWorkLogItem)r.DataBoundItem);

            if (logs.Count() == 0)
                return;

            foreach (var log in logs)
            {
                log.收付款人 = "钰";
                log.已收付货款 = log.货款合计;
            }

            _workLogService.Save(logs);
            dgv.RefreshVisibilityByRecordedStatus();

            selectedRows = GetSelectedAndVisibleRows(dgv);
            if (selectedRows == null || selectedRows.Count() == 0)
                this.Close();
        }

        private void btnGroupOrder_Click(object sender, EventArgs e)
        {
            IEnumerable<ExcelWorkLogItem> list = new SortableBindingList<ExcelWorkLogItem>();

            foreach (var group in _source.GroupBy(x => x.备注))
                list = list.Concat(group);

            var dgv = this.panelContainer.Controls[GRID_CONTROL_NAME] as DataGridView;
            dgv.DataSource = new SortableBindingList<ExcelWorkLogItem>(list);
        }
    }
}
